#region License
// Copyright 2008-2009 Jeremy Skinner (http://www.jeremyskinner.co.uk)
// 
// Licensed under the Apache License, Version 2.0 (the "License"); 
// you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at 
// 
// http://www.apache.org/licenses/LICENSE-2.0 
// 
// Unless required by applicable law or agreed to in writing, software 
// distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
// See the License for the specific language governing permissions and 
// limitations under the License.
// 
// The latest version of this file can be found at http://www.codeplex.com/FluentValidation
#endregion

using FluentValidation.Internal;

namespace FluentValidation.Tests {
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using NUnit.Framework;

	[TestFixture]
	public class ComplexValidationTester {
		

        public class PersonValidator : AbstractValidator<Person>
        {
            public PersonValidator()
            {
                RuleFor("Forename", x => x.Forename).NotNull();
                RuleFor("Address", x => x.Address).SetValidator(new AddressValidator());
            }
        }

        public class AddressValidator : AbstractValidator<Address>
        {
            public AddressValidator()
            {
                RuleFor("Postcode", x => x.Postcode).NotNull();
                RuleFor("Country", x => x.Country).SetValidator(new CountryValidator());
            }
        }

        public class CountryValidator : AbstractValidator<Country>
        {
            public CountryValidator()
            {
                RuleFor("Name", x => x.Name).NotNull();
            }
        }

        private PersonValidator _validator;
        private Person _person;

		[SetUp]
		public void Setup() {
			_validator = new PersonValidator();
			_person = new Person {
				Address = new Address {
                    //Line1 = "not empty",
                    //Postcode = "PE",
					Country = new Country()
				},
				Orders = new List<Order> {
					new Order { Amount = 5 },
                    new Order { ProductName = "Foo" }    	
                }
			};
		}

		[Test]
// ReSharper disable InconsistentNaming
		public void Validates_complex_property() {

			var results = _validator.Validate(_person);
            TestHelpers.OutputErrorsToConsole(results);
			results.Errors.Count.ShouldEqual(3);
			results.Errors[0].PropertyName.ShouldEqual("Forename");
			results.Errors[1].PropertyName.ShouldEqual("Address.Postcode");
			results.Errors[2].PropertyName.ShouldEqual("Address.Country.Name");
		}

        [Test]
        public void Complex_validator_should_not_be_invoked_on_null_property()
        {
            var results = _validator.Validate(new Person());
            TestHelpers.OutputErrorsToConsole(results);
            results.Errors.Count.ShouldEqual(1);
        }

        [Test]
        public void Should_allow_normal_rules_and_complex_property_on_same_property()
        {
            _validator.RuleFor("AddressLine1", x => x.Address.Line1).NotNull();
            var results = _validator.Validate(_person);
            TestHelpers.OutputErrorsToConsole(results);
            results.Errors.Count.ShouldEqual(4);
        }

        [Test]
        public void Explicitly_included_properties_should_be_propogated_to_nested_validators()
        {
            var exp = new NamedExpression<Person> {Identifier = "Address", Expression = x => x.Address};
            var results = _validator.Validate(_person, exp);
            TestHelpers.OutputErrorsToConsole(results);
            results.Errors.Count.ShouldEqual(2);
            results.Errors.First().PropertyName.ShouldEqual("Address.Postcode");
            results.Errors.Last().PropertyName.ShouldEqual("Address.Country.Name");
        }

        [Test]
        public void Explicitly_included_properties_should_be_propogated_to_nested_validators_using_strings()
        {
            var results = _validator.Validate(_person, "Address");
            TestHelpers.OutputErrorsToConsole(results);
            results.Errors.Count.ShouldEqual(2);
            results.Errors.First().PropertyName.ShouldEqual("Address.Postcode");
            results.Errors.Last().PropertyName.ShouldEqual("Address.Country.Name");
        }

        [Test]
        public void Complex_property_should_be_excluded()
        {
            var exp = new NamedExpression<Person> { Identifier = "Surname", Expression = x => x.Surname };
            var results = _validator.Validate(_person, exp);
            TestHelpers.OutputErrorsToConsole(results);
            results.Errors.Count.ShouldEqual(0);
        }

		private static string PointlessMethod() { return null; }

		public class PointlessStringValidator : AbstractValidator<string> {
			
		}
        // ReSharper restore InconsistentNaming
	}
}